#include "sc/context.h"
#include "sc/interface.h"
#include "sc/xml.h"

#include "boost/filesystem/operations.hpp"
#include "boost/filesystem/path.hpp"
#include "boost/regex.hpp"

#include "utils\traceur.h"

#include <sstream>

using namespace sc;

/**
* Load a context
*
* @param sFilenameSCC SCC file name
*
* @return loading error
*/
int Context::Load(const std::string& sFilenameSCC)
{
    int error = SCE_SHEMA_INVALID;

    m_sFilename = sFilenameSCC;

    // Load the SCC document
    m_sccDoc = xmlReadFile(sFilenameSCC.c_str(), NULL, 0);
    xmlNodePtr root = xmlDocGetRootElement(m_sccDoc);

    if (root && !xmlStrcmp(root->name, xml::_context))
    {
        error = SCE_NONE;

        xmlNodePtr child = root->children;
        while (child && !error)
        {
            if (child->type == XML_ELEMENT_NODE)
            {
                if (!xmlStrcmp(child->name, xml::_rng))
                {
                    // Load the config
                    const xmlChar* sRngFile = xmlNodeListGetString(m_sccDoc, child->children, 1);
                    if (sRngFile == NULL)
                    {
                        error = SCE_SHEMA_INVALID;
                    }
                    else
                    {
                        boost::filesystem::path pathSCC(sFilenameSCC);
                        boost::filesystem::path pathRNG(pathSCC.branch_path() / std::string((const char*) sRngFile));

                        error = m_setup.LoadConfig(pathRNG.string());
                    }
                }
                else if (!xmlStrcmp(child->name, xml::_setup))
                {
                }
                else if (!xmlStrcmp(child->name, xml::_mmi))
                {
                    error = LoadMMI(child);
                }
            }
            child = child->next;
        }
    }
    return error;
}

/**
* Load the MMI context
*  - the way to print label
*  - icon for the tree item
*
* @param pNodeMMI
*
* @return loading error
*/
int Context::LoadMMI(xmlNodePtr pNodeMMI)
{
    int error = SCE_NONE;

    xmlNodePtr child = pNodeMMI->children;
    while (child && !error)
    {
        if (child->type == XML_ELEMENT_NODE)
        {
            if (!xmlStrcmp(child->name, xml::_label))
            {
                // LABEL
                const xmlChar* sFor = xmlGetProp(child, xml::_for);
                if (sFor == NULL)
                {
                    error = SCE_SHEMA_INVALID;
                }
                else
                {
                    std::string sElement( (const char*) sFor );
                    const xmlChar* sValue = xmlGetProp(child, xml::_value);
                    const xmlChar* sIcon  = xmlGetProp(child, xml::_icon);

                    if (sValue)
                    {
                        // Load the label value
                        m_mapMMI[sElement].sValue = (const char*) sValue;
                    }
                    if (sIcon)
                    {
                        // Load the icon path
                        boost::filesystem::path pathSCC(m_sFilename);
                        boost::filesystem::path pathICO(pathSCC.branch_path() / (const char*) sIcon);
                        m_mapMMI[sElement].sIcon = pathICO.native_file_string();
                    }
                }
            }
        }
        child = child->next;
    }
    return error;
}

/**
* Get the label of the tree according to the context
*
* @param rcElement element of which we need the tree label
*
* @return label
*/
std::string Context::GetLabel(const Setup::Element& rcElement) const
{
Traceur::Printf("  Context::GetLabel(%s)", rcElement.GetName().c_str());

    std::string sLabel = rcElement.GetName();
    TMapMMI::const_iterator iter = m_mapMMI.find(sLabel);
    if (iter != m_mapMMI.end())
    {
        sLabel = (*iter).second.sValue;

Traceur::Printf("Context::GetLabel(%s) -> %s", rcElement.GetName().c_str(), sLabel.c_str());

        // Label is dynamic ?
        std::string::const_iterator start = sLabel.begin();
        std::string::const_iterator end   = sLabel.end();
        boost::match_results<std::string::const_iterator> what;
        boost::regex re_find("%([a-z]*)%");
        boost::match_flag_type flags = boost::match_default;
        while(regex_search(start, end, what, re_find, flags))
        {
            std::string sMatch(what[1].first, what[1].second);

Traceur::Printf(" * REGEX : match %s", sMatch.c_str());

            // Does the attribute exist ?
            Setup::TMapAttribut::const_iterator iterAtt = rcElement.GetAttributes().find(sMatch);
            if (iterAtt != rcElement.GetAttributes().end())
            {
                if (!(*iterAtt).second.m_sValue.empty())
                {
                    // Create the regex to replace dynamic info
                    std::ostringstream oss;
                    oss << "(%" << sMatch << "%)";

                    boost::regex re_replace(oss.str());
                    sLabel = boost::regex_replace(sLabel, re_replace, (*iterAtt).second.m_sValue);

Traceur::Printf(" * REGEX : new label %s", sLabel.c_str());
                }
                else
                {
                    // Attribute empty : We use the element name
                    sLabel = rcElement.GetName();
                }
            }
            // update search position:
            start = what[0].second;
            // update flags:
            flags |= (boost::match_prev_avail | boost::match_not_bob);
        }

        // If label is empty, we fill it with the element name
        if (sLabel.empty())
            sLabel = rcElement.GetName();
    }
    return sLabel;
}
